json = require "json"
--const
max_attempts = 3
--进入录音播报超时时间
timeout = 10000
digit_timeout = 3000
terminator = "#" --终止语音提示符
api = freeswitch.API()
core_server_ip = api:executeString("eval $${core_service_ip}")
external_ip = api:executeString("eval $${external_ip}")

local number,s_number,new,s_new,DATA = 0,'0',0,'0',nil
local break_dtmf,break_time1,break_time2 = {},0,0
CHINESE = "zh" 
ENGLISH = "en"
TOTAL_PAGE = 0 
PERPAGE = 10
READorNOT = 0 -- 是否已读
NEWLAST = false --是否是最后一个未读记录
DSE = true --是否设置语音信箱

account_user = session:getVariable("caller_id_number") --分机号
account_domain = "opbx"
----
local sound_prefix
local lan,pwd -- 语言，密码
local p =1 -- 页码
local l = 1 --第几条
-------
-- local ExitAction
--functions
--输出表
function print_r(array)
    -- body
    for key,value in ipairs(array) 
    do
      freeswitch.consoleLog("INFO","key:"..key .. ";value:"..value) 
    end
end

--设置语音路劲
function setSoundPrefix()
    -- body
    sound_prefix = "/usr/local/freeswitch/sounds/zh/cn/link/voicemail/yunpbx"
    if(lan == ENGLISH) then
        sound_prefix = "/usr/local/freeswitch/sounds/en/us/callie/voicemail/yunpbx"
    end
    session:setVariable('sound_prefix',sound_prefix)
    freeswitch.consoleLog("INFO",'language is '.. lan ..' and filepath is '.. sound_prefix )
end

function goodbye()
    if not session:ready() then return end
    freeswitch.consoleLog('INFO',"say goodbye,exit voicemail!")
    if(DSE == false) then    
        local zh = "/usr/local/freeswitch/sounds/zh/cn/link/voicemail/yunpbx/"
        local en = "/usr/local/freeswitch/sounds/en/us/callie/voicemail/yunpbx/"
        session:sleep(200) 
        session:streamFile(zh .. "vm-voicemail_not_available.wav")
        session:sleep(200) 
        session:streamFile(zh .. "vm-goodbye.wav")
        session:sleep(200) 
        session:streamFile(en .. "vm-voicemail_not_available.wav")
        session:sleep(200) 
        session:streamFile(en .. "vm-goodbye.wav")
        session:sleep(200) 
        return 
    end
    session:streamFile("vm-goodbye.wav")
    session:hangup()
end

--放音控制
function onInputCBF(s,_type,obj,arg)
    if not session:ready() then return end
    if(_type == "dtmf") then
        break_time2 = api:getTime()
        session:consoleLog("INFO"," between two press time is " .. (break_time2 - break_time1) .. 'ms')
        session:consoleLog("INFO","break_dtmf is " .. obj['digit'])
        if(break_time2 - break_time1 < 500) then
            break_dtmf[2] = obj['digit']
        else
            break_dtmf[1] = obj['digit']
        end
        break_time1 = break_time2
        return "break"
    end
end

--通信函数
function tocurl(section,k,v,k1,v1)
    local field1,field2 = "",""
    if(k ~= nil) then
        field1 = " -d "..k.."=" .. v 
    end
    if(k1 ~= nil) then
         field2 = " -d "..k1.."=" .. v1
    end
    local handle = io.popen("curl -d section="..section.." -d station=" .. account_user  ..field1 ..field2 .. " http://"..core_server_ip..":8080/switch/voicemail")
    local result = handle:read("*a")
    handle:close()
    session:consoleLog("INFO","get result is " .. result)
    if(result == '' or result == '{}' or result == '[]') then
        session:consoleLog("NOTICE","tocurl data is empty ")
        return nil
    else
        return json.decode(result)
    end
end

--结束行为
function ExitAction()
    -- body
    freeswitch.consoleLog('INFO','fire event:SWITCH_EVENT_MESSAGE_WAITING')
    local j = tocurl('getnumber')
    local number,new = tonumber(j[1]),tonumber(j[2])
    local msg = new ..'/' .. (number-new) 
    local yn = 'no'
    if(new > 0) then yn = "yes" end
    local event = freeswitch.Event("SWITCH_EVENT_MESSAGE_WAITING")
    event:addHeader("MWI-Messages-Waiting", yn)
    event:addHeader("MWI-Message-Account", "user/"..account_user .. "@" ..external_ip)
    event:addHeader("MWI-Voice-Message", msg)
    event:fire()
end
--挂机回调函数
function onHangUpHook(s,status,arg)
    -- body
    freeswitch.consoleLog('INFO',"onHangUpHook: " .. status .. "\n")
    if(DSE) then ExitAction() end
    return 'die'
end
--标记已读
function brandThis()
    if not session:ready() then return end
    local j = tocurl("brand",'id',DATA[l].id)
    if(j.state == 200) then
        session:consoleLog('INFO','brand ok!')
    else
        session:consoleLog("ERR",'brand error!')
    end
end
-- 删除记录
function delete_cur_record()
    if not session:ready() then return end
    local j = tocurl("delrec",'id',DATA[l].id) -- 是否需要删除口令？
    if(j.isdelete == 200) then 
        table.remove(DATA, l);
        number = table.maxn(DATA)
        session:streamFile('vm-deleted.wav')
        session:sleep(500)
        -- vm_ivr()
    else
        --系统删除错误
        session:consoleLog('ERR',"delete file error")
        session:streamFile('vm-undeleted.wav')
        -- goodbye()
    end
end
--获取语音信箱数据
function get_voicemail_data()
    if not session:ready() then return end
    local j = tocurl("info")
    if(j == {} or j == nil) then 
        DSE = false 
        return
    end
    lan,pwd = j.lan,j.pwd
    if(lan == nil or lan == '') then
        lan = 'zh'
    end
end
--获取留言数据
function get_voice_list()
    if not session:ready() then return end
    DATA = tocurl("lists",'is_listened' ,READorNOT)
    number = #DATA
    if(READorNOT == 0) then
        session:consoleLog("INFO","new message count is " .. number)
    else
        session:consoleLog("INFO"," listened message count is " .. number )
    end
end
--获取留言数量
function get_num()
    --查询数量
    if not session:ready() then return end
    local j = tocurl("getnumber")
    s_number,s_new = j[1],j[2]
     session:consoleLog("INFO","all message count is " .. s_number .. ",new message is " .. s_new)
     number,new = tonumber(s_number),tonumber(s_new)
end
--获取语音数据地址
function getPath(url)
    if not session:ready() then return end
    local j = tocurl("getdata","url",url)
    return j.url
end
--转到已收听留言
function to_listend_box()
    if not session:ready() then return end
    READorNOT = 1
    get_voice_list()
    if(number > 0) then
        session:streamFile("vm-you_have.wav")
        session:sayPhrase("voicemail_say_number", number, lan)
        session:streamFile("vm-list_listened_msg.wav")
        l = 1
        play()
    else
        session:streamFile("vm-no_saved_msg.wav")
    end
end
--新留言听完ivr
function no_new_msg_ivr( )
    -- body
    local digits = session:playAndGetDigits(1,1,3,timeout,terminator,"vm-goto_listened.wav","vm-inputwrong.wav","^1$")
    if(digits == '1') then
        to_listend_box()
    end
end
--录音播放完ivr
function afterPlayIVR()
    local digits,ivr_music,regexp
    if(l >= number and READorNOT ==0) then
        ExitAction()
        --最后一条录音
        ivr_music,regexp = "vm-after_last_new.wav", "^(1|3|0|\\*)$"
    else
        ivr_music,regexp = "vm-after_listen_new.wav","^(1|2|3|\\*)$"
    end
    digits = session:playAndGetDigits(1,1,3,timeout,terminator,ivr_music,"vm-inputwrong.wav",regexp)
    session:consoleLog("info", "Got DTMF digits: ".. digits .."\n")
    if(digits == "0") then
        --收听已听过的
        to_listend_box()
    end
    if(digits == "1") then
        --电话回拨
        print_r(DATA[l])
        session:transfer(DATA[l].callerIdNumber, "XML", account_domain)
    end
    if(digits == "2") then
        --收听下一条
        l = l+1
        if(l > number) then
            l = 1
        end
        play()
    end
    if(digits == "3") then
      --删除
        delete_cur_record()
        -- s是新留言的情况已被处理
        -- 处理已收听留言
        if(READorNOT == 0) then
            if(l > number) then
                no_new_msg_ivr()
            else
                play()
            end
        else
            if(number >0 and l>number) then
                l = 1
                play()
            elseif(number == 0) then
                session:streamFile("vm-no_more_messages.wav")
                return 
            else
                play()
            end

        end
       
    end
    if(digits == "*") then
        play(1)
    end
end
-- 播放录音
function play(sign)
    if(lan == CHINESE) then
        session:streamFile("vm-the.wav")
    end
    session:sayPhrase("voicemail_say_number", l, lan)
    if(lan == CHINESE) then
        session:streamFile("vm-list.wav")
        session:sleep(500)
        session:sayPhrase("yunpbx_voicemail_time", DATA[l].createTime, lan)
    else
        session:sleep(500)

        session:sayPhrase("voicemail_say_date", DATA[l].createTime, lan)
    end
    session:sleep(500)
    session:sayPhrase("voicemail_say_phone_number", DATA[l].callerIdNumber, lan)
    if(lan == CHINESE) then
        session:streamFile("vm-leave_msg.wav")
    end
    session:sleep(500)
    session:streamFile("tone_stream://%(1000,0,1000)")
    session:sleep(500)
    -- session:setInputCallback('onInputCBF','')
    session:streamFile(DATA[l].dev)
    -- session:unsetInputCallback()
    if(sign == nil and READorNOT == 0) then
        brandThis() --标记为已读
    end
    afterPlayIVR()
end

-- 起点
function core_service()
--核心控制
    if not session:ready() then return end
    get_num()
    session:streamFile("vm-you_have.wav")
    session:sayPhrase("voicemail_say_number", new, lan)
    session:streamFile("vm-list_new_msg.wav")
    if(new > 0 ) then 
        READorNOT = 0
        get_voice_list()
        session:sleep(200)
        play()
    elseif(number - new >0) then
        no_new_msg_ivr()
    else
        session:streamFile("vm-no_more_messages.wav")
    end
end
-- 欢迎语
function greeting(wrong_count)
    if not session:ready() then return end
    -- if(lan == CHINESE) then
    
    if(pwd ~= nil or pwd ~= '') then
        if(wrong_count == 0) then
            session:streamFile('vm-greeting.wav')
            session:sleep(500)
            session:consoleLog('INFO','table =' .. table.concat(break_dtmf,','))
            if(break_dtmf == {}) then
                session:consoleLog('INFO','table is empty')
            end
            if(wrong_count == 0  and (next(break_dtmf) == nil or break_dtmf[1] == '#')) then
                session:streamFile("vm-enter_pass.wav")
            end
        end
        -- 设计直拨输入密码
        local n = table.maxn(break_dtmf) 
        local c = ''
        local ignore = false
        if(n == 1 and break_dtmf[1] ~= '#') then
            c = break_dtmf[1]
        end
        if(n > 1 and break_dtmf[n] == '#') then
            ignore = true
            c = table.concat( break_dtmf, nil,1,n-1)
        elseif(n>1 and break_dtmf[n] ~= '#') then
            c = table.concat( break_dtmf, nil)
        end
        session:consoleLog("info", "Got break DTMF digits: ".. c .."\n")

        local digits = ''
        if(ignore == false) then
            digits = session:getDigits(15,terminator,timeout)
        end
        session:consoleLog("info", "Got DTMF digits: ".. digits .."\n")
        session:consoleLog("info", " digits: ".. c .. tostring(digits) .."\n")
       
        if( c .. tostring(digits) == pwd ) then
            break_dtmf = {}
            freeswitch.consoleLog('INFO',"password is correct!")
        else
            break_dtmf = {}
            wrong_count = wrong_count + 1
            if(wrong_count >= 3) then
                session:streamFile("vm-lastinput_wrong.wav")
                goodbye()
            else
                session:streamFile("vm-inputwrong.wav")
                greeting(wrong_count)
            end
        end
    end
end

--run

session:answer()
freeswitch.consoleLog("INFO",account_user .."@" .. account_domain .. "->comeing voicemail")
local run = function ( )
    -- body
    get_voicemail_data()
    if( DSE == false) then
        session:consoleLog("INFO",'the '..account_user ..'@'..account_domain..' didn`t sett voicemail ')
    else
        setSoundPrefix()
        session:setHangupHook('onHangUpHook',"w00t")
        session:check_hangup_hook()
        session:sleep(500)
        session:consoleLog("INFO","pwd is " ..  pwd ..", type is " .. type(pwd))
        --设置钩子
        --进入语音信箱，密码
        session:setInputCallback('onInputCBF','')
        greeting(0)
        -- session:unsetInputCallback()
        core_service()
        --核心流程
    end
    --结束语
    goodbye()
end

local result,err = pcall(run)
if(result == true) then
        freeswitch.consoleLog('INFO','core_service success') 
    else
        freeswitch.consoleLog('INFO','get error:'..err) 
    end
